and remove the use of xc_vcpu_getcontext() from HVM save/restore.
Also fixes loss of CR2, DR6 and DR7 contents across HVM save/restore.
Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com>
xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_EVTCHN, store_evtchn);
*store_mfn = magic_pfns[2];
- /* Read vcpu contexts */
- for ( i = 0; i <= max_vcpu_id; i++ )
- {
- if ( !(vcpumap & (1ULL << i)) )
- continue;
-
- if ( !read_exact(io_fd, &(ctxt), sizeof(ctxt)) )
- {
- ERROR("error read vcpu context.\n");
- goto out;
- }
-
- if ( (rc = xc_vcpu_setcontext(xc_handle, dom, i, &ctxt)) )
- {
- ERROR("Could not set vcpu context, rc=%d", rc);
- goto out;
- }
- rc = 1;
- }
-
/* Read HVM context */
if ( !read_exact(io_fd, &rec_len, sizeof(uint32_t)) )
{
static int suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd,
- int dom, xc_dominfo_t *info,
- vcpu_guest_context_t *ctxt)
+ int dom, xc_dominfo_t *info)
{
int i = 0;
return -1;
}
- if ( xc_vcpu_getcontext(xc_handle, dom, 0, ctxt) )
- ERROR("Could not get vcpu context");
-
-
if ( info->dying )
{
ERROR("domain is dying");
static xen_pfn_t *map_and_save_p2m_table(int xc_handle,
int io_fd,
uint32_t dom,
- vcpu_guest_context_t *ctxt,
unsigned long p2m_size,
shared_info_t *live_shinfo)
{
+ vcpu_guest_context_t ctxt;
+
/* Double and single indirect references to the live P2M table */
xen_pfn_t *live_p2m_frame_list_list = NULL;
xen_pfn_t *live_p2m_frame_list = NULL;
}
}
+ if ( xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt) )
+ {
+ ERROR("Could not get vcpu context");
+ goto out;
+ }
+
/*
* Write an extended-info structure to inform the restore code that
* a PAE guest understands extended CR3 (PDPTs above 4GB). Turns off
* slow paths in the restore code.
*/
if ( (pt_levels == 3) &&
- (ctxt->vm_assist & (1UL << VMASST_TYPE_pae_extended_cr3)) )
+ (ctxt.vm_assist & (1UL << VMASST_TYPE_pae_extended_cr3)) )
{
unsigned long signature = ~0UL;
uint32_t tot_sz = sizeof(struct vcpu_guest_context) + 8;
!write_exact(io_fd, &tot_sz, sizeof(tot_sz)) ||
!write_exact(io_fd, &chunk_sig, 4) ||
!write_exact(io_fd, &chunk_sz, sizeof(chunk_sz)) ||
- !write_exact(io_fd, ctxt, sizeof(*ctxt)) )
+ !write_exact(io_fd, &ctxt, sizeof(ctxt)) )
{
ERROR("write: extended info");
goto out;
return 1;
}
- if ( xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt) )
- {
- ERROR("Could not get vcpu context");
- goto out;
- }
shared_info_frame = info.shared_info_frame;
/* Map the shared info frame */
else
{
/* This is a non-live suspend. Suspend the domain .*/
- if ( suspend_and_state(suspend, xc_handle, io_fd, dom, &info, &ctxt) )
+ if ( suspend_and_state(suspend, xc_handle, io_fd, dom, &info) )
{
ERROR("Domain appears not to have suspended");
goto out;
/* Map the P2M table, and write the list of P2M frames */
live_p2m = map_and_save_p2m_table(xc_handle, io_fd, dom,
- &ctxt, p2m_size, live_shinfo);
+ p2m_size, live_shinfo);
if ( live_p2m == NULL )
{
ERROR("Failed to map/save the p2m frame list");
DPRINTF("Start last iteration\n");
last_iter = 1;
- if ( suspend_and_state(suspend, xc_handle, io_fd, dom, &info,
- &ctxt) )
+ if ( suspend_and_state(suspend, xc_handle, io_fd, dom, &info) )
{
ERROR("Domain appears not to have suspended");
goto out;
}
- DPRINTF("SUSPEND shinfo %08lx eip %08lx edx %08lx\n",
- info.shared_info_frame,
- (unsigned long)ctxt.user_regs.eip,
- (unsigned long)ctxt.user_regs.edx);
+ DPRINTF("SUSPEND shinfo %08lx\n", info.shared_info_frame);
}
if ( xc_shadow_control(xc_handle, dom,
goto out;
}
- /* Save vcpu contexts */
-
- for ( i = 0; i <= info.max_vcpu_id; i++ )
- {
- if ( !(vcpumap & (1ULL << i)) )
- continue;
-
- if ( xc_vcpu_getcontext(xc_handle, dom, i, &ctxt) )
- {
- ERROR("HVM:Could not get vcpu context");
- goto out;
- }
-
- DPRINTF("write vcpu %d context.\n", i);
- if ( !write_exact(io_fd, &(ctxt), sizeof(ctxt)) )
- {
- ERROR("write vcpu context failed!\n");
- goto out;
- }
- }
-
/* Get HVM context from Xen and save it too */
if ( (rec_size = xc_domain_hvm_getcontext(xc_handle, dom, hvm_buf,
hvm_buf_size)) == -1 )
}
}
+ if ( xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt) )
+ {
+ ERROR("Could not get vcpu context");
+ goto out;
+ }
+
/* Canonicalise the suspend-record frame number. */
if ( !translate_mfn_to_pfn(&ctxt.user_regs.edx) )
{
{
struct vcpu *v;
struct hvm_hw_cpu ctxt;
+ struct vcpu_guest_context *vc;
for_each_vcpu(d, v)
{
if ( test_bit(_VPF_down, &v->pause_flags) )
continue;
+ /* Architecture-specific vmcs/vmcb bits */
hvm_funcs.save_cpu_ctxt(v, &ctxt);
+
+ /* Other vcpu register state */
+ vc = &v->arch.guest_context;
+ if ( vc->flags & VGCF_i387_valid )
+ memcpy(ctxt.fpu_regs, &vc->fpu_ctxt, sizeof(ctxt.fpu_regs));
+ else
+ memset(ctxt.fpu_regs, 0, sizeof(ctxt.fpu_regs));
+ ctxt.rax = vc->user_regs.eax;
+ ctxt.rbx = vc->user_regs.ebx;
+ ctxt.rcx = vc->user_regs.ecx;
+ ctxt.rdx = vc->user_regs.edx;
+ ctxt.rbp = vc->user_regs.ebp;
+ ctxt.rsi = vc->user_regs.esi;
+ ctxt.rdi = vc->user_regs.edi;
+ /* %rsp handled by arch-specific call above */
+#ifdef __x86_64__
+ ctxt.r8 = vc->user_regs.r8;
+ ctxt.r9 = vc->user_regs.r9;
+ ctxt.r10 = vc->user_regs.r10;
+ ctxt.r11 = vc->user_regs.r11;
+ ctxt.r12 = vc->user_regs.r12;
+ ctxt.r13 = vc->user_regs.r13;
+ ctxt.r14 = vc->user_regs.r14;
+ ctxt.r15 = vc->user_regs.r15;
+#endif
+ ctxt.dr0 = vc->debugreg[0];
+ ctxt.dr1 = vc->debugreg[1];
+ ctxt.dr2 = vc->debugreg[2];
+ ctxt.dr3 = vc->debugreg[3];
+ ctxt.dr6 = vc->debugreg[6];
+ ctxt.dr7 = vc->debugreg[7];
+
if ( hvm_save_entry(CPU, v->vcpu_id, h, &ctxt) != 0 )
return 1;
}
static int hvm_load_cpu_ctxt(struct domain *d, hvm_domain_context_t *h)
{
- int vcpuid;
+ int vcpuid, rc;
struct vcpu *v;
struct hvm_hw_cpu ctxt;
+ struct vcpu_guest_context *vc;
/* Which vcpu is this? */
vcpuid = hvm_load_instance(h);
gdprintk(XENLOG_ERR, "HVM restore: domain has no vcpu %u\n", vcpuid);
return -EINVAL;
}
+ vc = &v->arch.guest_context;
+
+ /* Need to init this vcpu before loading its contents */
+ LOCK_BIGLOCK(d);
+ if ( !v->is_initialised )
+ if ( (rc = boot_vcpu(d, vcpuid, vc)) != 0 )
+ return rc;
+ UNLOCK_BIGLOCK(d);
if ( hvm_load_entry(CPU, h, &ctxt) != 0 )
return -EINVAL;
+ /* Architecture-specific vmcs/vmcb bits */
if ( hvm_funcs.load_cpu_ctxt(v, &ctxt) < 0 )
return -EINVAL;
+ /* Other vcpu register state */
+ memcpy(&vc->fpu_ctxt, ctxt.fpu_regs, sizeof(ctxt.fpu_regs));
+ vc->user_regs.eax = ctxt.rax;
+ vc->user_regs.ebx = ctxt.rbx;
+ vc->user_regs.ecx = ctxt.rcx;
+ vc->user_regs.edx = ctxt.rdx;
+ vc->user_regs.ebp = ctxt.rbp;
+ vc->user_regs.esi = ctxt.rsi;
+ vc->user_regs.edi = ctxt.rdi;
+ vc->user_regs.esp = ctxt.rsp;
+#ifdef __x86_64__
+ vc->user_regs.r8; = ctxt.r8;
+ vc->user_regs.r9; = ctxt.r9;
+ vc->user_regs.r10 = ctxt.r10;
+ vc->user_regs.r11 = ctxt.r11;
+ vc->user_regs.r12 = ctxt.r12;
+ vc->user_regs.r13 = ctxt.r13;
+ vc->user_regs.r14 = ctxt.r14;
+ vc->user_regs.r15 = ctxt.r15;
+#endif
+ vc->debugreg[0] = ctxt.dr0;
+ vc->debugreg[1] = ctxt.dr1;
+ vc->debugreg[2] = ctxt.dr2;
+ vc->debugreg[3] = ctxt.dr3;
+ vc->debugreg[6] = ctxt.dr6;
+ vc->debugreg[7] = ctxt.dr7;
+
+ vc->flags = VGCF_i387_valid | VGCF_online;
+ v->fpu_initialised = 1;
+
/* Auxiliary processors should be woken immediately. */
if ( test_and_clear_bit(_VPF_down, &v->pause_flags) )
vcpu_wake(v);
{
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- c->eip = vmcb->rip;
+ c->rip = vmcb->rip;
#ifdef HVM_DEBUG_SUSPEND
printk("%s: eip=0x%"PRIx64".\n",
inst_len, c->eip);
#endif
- c->esp = vmcb->rsp;
- c->eflags = vmcb->rflags;
+ c->rsp = vmcb->rsp;
+ c->rflags = vmcb->rflags;
c->cr0 = v->arch.hvm_svm.cpu_shadow_cr0;
+ c->cr2 = v->arch.hvm_svm.cpu_cr2;
c->cr3 = v->arch.hvm_svm.cpu_cr3;
c->cr4 = v->arch.hvm_svm.cpu_shadow_cr4;
unsigned long mfn, old_base_mfn;
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
- vmcb->rip = c->eip;
- vmcb->rsp = c->esp;
- vmcb->rflags = c->eflags;
+ vmcb->rip = c->rip;
+ vmcb->rsp = c->rsp;
+ vmcb->rflags = c->rflags;
v->arch.hvm_svm.cpu_shadow_cr0 = c->cr0;
vmcb->cr0 = c->cr0 | X86_CR0_WP | X86_CR0_ET;
if ( !paging_mode_hap(v->domain) )
vmcb->cr0 |= X86_CR0_PG;
+ v->arch.hvm_svm.cpu_cr2 = c->cr2;
+
#ifdef HVM_DEBUG_SUSPEND
printk("%s: cr3=0x%"PRIx64", cr0=0x%"PRIx64", cr4=0x%"PRIx64".\n",
__func__,
vmcb->sysenter_esp = c->sysenter_esp;
vmcb->sysenter_eip = c->sysenter_eip;
+ vmcb->dr6 = c->dr6;
+ vmcb->dr7 = c->dr7;
+
paging_update_paging_modes(v);
return 0;
data->msr_cstar = vmcb->cstar;
data->msr_syscall_mask = vmcb->sfmask;
data->msr_efer = v->arch.hvm_svm.cpu_shadow_efer;
+ data->msr_flags = -1ULL;
data->tsc = hvm_get_guest_time(v);
}
int vmx_vmcs_save(struct vcpu *v, struct hvm_hw_cpu *c)
{
- c->eip = __vmread(GUEST_RIP);
- c->esp = __vmread(GUEST_RSP);
- c->eflags = __vmread(GUEST_RFLAGS);
+ c->rip = __vmread(GUEST_RIP);
+ c->rsp = __vmread(GUEST_RSP);
+ c->rflags = __vmread(GUEST_RFLAGS);
c->cr0 = v->arch.hvm_vmx.cpu_shadow_cr0;
+ c->cr2 = v->arch.hvm_vmx.cpu_cr2;
c->cr3 = v->arch.hvm_vmx.cpu_cr3;
c->cr4 = v->arch.hvm_vmx.cpu_shadow_cr4;
vmx_vmcs_enter(v);
- __vmwrite(GUEST_RIP, c->eip);
- __vmwrite(GUEST_RSP, c->esp);
- __vmwrite(GUEST_RFLAGS, c->eflags);
+ __vmwrite(GUEST_RIP, c->rip);
+ __vmwrite(GUEST_RSP, c->rsp);
+ __vmwrite(GUEST_RFLAGS, c->rflags);
v->arch.hvm_vmx.cpu_shadow_cr0 = c->cr0;
__vmwrite(CR0_READ_SHADOW, v->arch.hvm_vmx.cpu_shadow_cr0);
+ v->arch.hvm_vmx.cpu_cr2 = c->cr2;
+
#ifdef HVM_DEBUG_SUSPEND
printk("vmx_vmcs_restore: cr3=0x%"PRIx64", cr0=0x%"PRIx64", cr4=0x%"PRIx64".\n",
c->cr3,
__vmwrite(GUEST_SYSENTER_ESP, c->sysenter_esp);
__vmwrite(GUEST_SYSENTER_EIP, c->sysenter_eip);
+ __vmwrite(GUEST_DR7, c->dr7);
+
vmx_vmcs_exit(v);
paging_update_paging_modes(v);
data->shadow_gs = guest_state->shadow_gs;
/* save msrs */
- data->flags = guest_flags;
+ data->msr_flags = guest_flags;
data->msr_lstar = guest_state->msrs[VMX_INDEX_MSR_LSTAR];
data->msr_star = guest_state->msrs[VMX_INDEX_MSR_STAR];
data->msr_cstar = guest_state->msrs[VMX_INDEX_MSR_CSTAR];
struct vmx_msr_state *guest_state = &v->arch.hvm_vmx.msr_state;
/* restore msrs */
- guest_state->flags = data->flags;
+ guest_state->flags = data->msr_flags;
guest_state->msrs[VMX_INDEX_MSR_LSTAR] = data->msr_lstar;
guest_state->msrs[VMX_INDEX_MSR_STAR] = data->msr_star;
guest_state->msrs[VMX_INDEX_MSR_CSTAR] = data->msr_cstar;
*/
struct hvm_hw_cpu {
- uint64_t eip;
- uint64_t esp;
- uint64_t eflags;
+ uint8_t fpu_regs[512];
+
+ uint64_t rax;
+ uint64_t rbx;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rbp;
+ uint64_t rsi;
+ uint64_t rdi;
+ uint64_t rsp;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+
+ uint64_t rip;
+ uint64_t rflags;
+
uint64_t cr0;
+ uint64_t cr2;
uint64_t cr3;
uint64_t cr4;
+ uint64_t dr0;
+ uint64_t dr1;
+ uint64_t dr2;
+ uint64_t dr3;
+ uint64_t dr6;
+ uint64_t dr7;
+
uint32_t cs_sel;
uint32_t ds_sel;
uint32_t es_sel;
/* msr for em64t */
uint64_t shadow_gs;
- uint64_t flags;
/* msr content saved/restored. */
+ uint64_t msr_flags;
uint64_t msr_lstar;
uint64_t msr_star;
uint64_t msr_cstar;